/*
===============================================================================
                           NewStatusNotify plugin

This plugin notifies you when a contact changes his/hers status with a PopUp.
You can customize its look (style of popup, font, text...) and behaviour (the
position in the screen, the time to live, the action on a mouse click).

File name: "indiv_sounds.c"
This file contains the code for individual sound support.

Written by: Hrk (Luca Santarelli)

Miranda IM can be found here:
http://miranda-im.org/

===============================================================================
*/

#define STRICT
#define WIN32_LEAN_AND_MEAN

#include "headers.h"

/*
Rainwater told me he was going to add a routine to get Miranda's path in a couple of hours.
This was more or less a month ago.
This is the reason you'll get an error trying to open m_utils-path.h: it doesn't exist in the official CVS.
Blame Rainwater. (I guess this is not a good thing to say but HELL, if the devs don't help us plugin developers, why should I lie?)
Oh well, I woke up on the wrong side of the bed today 8)
*/



#ifndef OPENFILENAME_SIZE_VERSION_400
#define OPENFILENAME_SIZE_VERSION_400 sizeof(OPENFILENAME)
#endif

#define NICK_COLUMN      140
#define STATUS_COLUMN 110

extern const char* ModuleName;
extern aStatus StatusesList[];
extern void Log(char*);
extern MYOPTIONS MyOptions;
extern HINSTANCE hInst;

static void ResetListOptions(HWND);

//Declarations
BOOL CALLBACK DlgProcSoundOpts(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK DlgProcSoundUIPage(HWND, UINT, WPARAM, LPARAM);
int UserInfoInitialise(WPARAM, LPARAM);
static BOOL RemoveSoundFromList(HWND);
static BOOL SelectSound(HWND);
static BOOL PreviewSound(HWND, int);
HIMAGELIST GetStatusIconsImgList(char*);

//NewKindOfOptionsPage
static void ResetListOptions(HWND);
HWND hCListClone = NULL;

//Definitions
static BOOL PreviewSound(HWND hList, int status)
	{
	int iSel = ListView_GetSelectionMark(hList);
	if ( iSel > -1 ) 
		{
		TCHAR str[MAX_PATH] = { 0 };
		//Let's read the file name:
		ListView_GetItemText(hList, ListView_GetNextItem(hList, -1, LVNI_SELECTED), 1, str, sizeof(str));
		//If the string is "(default sound)", we want to hear the default sound indeed ;-)
		if (lstrcmp(str, TranslateT("(default sound)")) == 0)
			{
			if (status==1) 
				SkinPlaySound("UserFromOffline");
			else 
				SkinPlaySound(StatusesList[Index(status)].lpzSkinSoundName);
			}
		else { //We have a configured sound.
//			char szSoundFile[MAX_PATH] = { 0 };
			TCHAR szTranslatedSoundFile[MAX_PATH] = { 0 };
/*#ifdef UNICODE
									WideCharToMultiByte(CP_ACP,0,str,-1,szSoundFile,MAX_PATH,0,0);
									CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)szSoundFile, (LPARAM)szTranslatedSoundFile);
#else
									CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)str, (LPARAM)szTranslatedSoundFile);
#endif
*/
			CallService(MS_UTILS_PATHTOABSOLUTET, (WPARAM)str, (LPARAM)szTranslatedSoundFile);
#ifdef MS_SKIN_PLAYSOUNDEX
			if (ServiceExists(MS_SKIN_PLAYSOUNDEX))
				{
				SkinPlaySoundEx(szTranslatedSoundFile);
				}
			else 
#endif
#ifdef RegIndivSounds
			 		SkinPlaySound(szTranslatedSoundFile); 
#else
				{
				if (MyOptions.AvoidClipping)
					PlaySound(szTranslatedSoundFile, NULL, SND_ASYNC | SND_FILENAME | SND_NOSTOP);
				else
					PlaySound(szTranslatedSoundFile, NULL, SND_ASYNC | SND_FILENAME);
				}
#endif
		}
	}
	return TRUE;
}

//Returns TRUE on sound change, FALSE on error.
static BOOL RemoveSoundFromList(HWND hList)
{
	int iSel = ListView_GetNextItem(hList, -1, LVNI_SELECTED);
	if (iSel > -1)
		{
		LVITEM lvitem = { 0 };
		TCHAR str[MAX_PATH] = { 0 };

		lvitem.mask = LVIF_PARAM;
		lvitem.iItem = iSel;

		ListView_GetItemText(hList,iSel,1,str,sizeof(str));
		if (lstrcmp(str, TranslateT("(default sound)"))==0)
			return FALSE;
		else
			{ //We cycle on the selected items.
			iSel = -1;
			while ((iSel = ListView_GetNextItem(hList, iSel, LVNI_SELECTED)) != -1)
				//ListView_SetItemText(hList, iSel, 1, Translate("(default sound)"));
				{
				LV_ITEM _ms_lvi;
				_ms_lvi.iSubItem = 1;
				_ms_lvi.pszText = TranslateT("(default sound)");
				SNDMSG(hList, LVM_SETITEMTEXT, (WPARAM)iSel, (LPARAM)(LV_ITEM *)&_ms_lvi);
				}
			return TRUE;
			}
		}
	else //There is no contact selected.
		return FALSE;
}

//Returns TRUE on sound change, FALSE on error.
static BOOL SelectSound(HWND hwndDlg) {
	TCHAR str[MAX_PATH] = { 0 };
	OPENFILENAME ofn = { 0 };
	HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST);

	int iSel = ListView_GetNextItem(hList, -1, LVNI_SELECTED);
	if (iSel <= -1) return FALSE;

	ListView_GetItemText(hList,ListView_GetNextItem(hList,-1,LVNI_SELECTED),1,str,sizeof(str));
	ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
	ofn.hwndOwner = GetParent(hwndDlg);
	ofn.hInstance = NULL;
	ofn.lpstrFilter = _T("Wave Files (*.wav)\0*.WAV\0All Files (*)\0*\0");
	ofn.lpstrFile = str;
	ofn.Flags = OFN_FILEMUSTEXIST;
	ofn.nMaxFile = sizeof(str);
	ofn.nMaxFileTitle = MAX_PATH;
	ofn.lpstrDefExt = _T("wav");
	if(!GetOpenFileName(&ofn)) return FALSE;
	//Now let's change the text in the listview. We cycle on the selected items (so that people may choose more than one status)
	iSel = -1;
	while ((iSel = ListView_GetNextItem(hList, iSel, LVNI_SELECTED)) != -1) {
		ListView_SetItemText(hList, iSel,1,str);
	}
	return TRUE;
}

HIMAGELIST GetStatusIconsImgList(char * lpzProto) {
	HIMAGELIST hList = NULL;
	hList = ImageList_Create(GetSystemMetrics(SM_CXSMICON), //cx
			GetSystemMetrics(SM_CYSMICON), //cy
			((LOBYTE(LOWORD(GetVersion()))>=5 && LOWORD(GetVersion())!=5)?ILC_COLOR32:ILC_COLOR16)|ILC_MASK, //flags
			10, //cInitial: the number of initial images: the statuses are 10!
			0); //cGrow: we'll not add any other icon to the list.

	if (hList != NULL && lpzProto != NULL) { //The list was made, add the icons to it.
		int i = 0;
		for (i = ID_STATUS_MIN; i <= ID_STATUS_MAX; i++) {
			ImageList_AddIcon(hList, LoadSkinnedProtoIcon(lpzProto, StatusesList[Index(i)].ID));
		}
	}
	return hList;
}

//========== Individual Sounds: UserInfo page ==========
BOOL CALLBACK DlgProcSoundUIPage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
	static HANDLE hContact = NULL;
	switch (msg) {
		case WM_INITDIALOG: 
			{
			LV_COLUMN lvc = { 0 };
			HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST);
			RECT aRect = { 0 };
			int i;
			char* lpzProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)lParam,0);
			
			//Let's get an image list with the status icons.
			HIMAGELIST hImgList = GetStatusIconsImgList(lpzProto);

			hContact = (HANDLE)lParam;
			ListView_SetImageList(hList, hImgList, LVSIL_SMALL);
			ImageList_AddIcon(hImgList, LoadSkinnedIcon(SKINICON_OTHER_USERONLINE)); // icon for UserFromOffline sound
			GetClientRect(hList, &aRect);
			lvc.mask = LVCF_WIDTH | LVCF_TEXT;
			ListView_SetExtendedListViewStyleEx(hList,
					LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP,
					LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
			lvc.cx = STATUS_COLUMN;
			lvc.pszText = TranslateT("Status");
			SNDMSG((hList), LVM_INSERTCOLUMN, 0, (LPARAM)(const LV_COLUMN *)(&lvc));
			lvc.cx = aRect.right - STATUS_COLUMN - GetSystemMetrics(SM_CXVSCROLL);
			lvc.pszText = TranslateT("Sound for the status");
			SNDMSG((hList), LVM_INSERTCOLUMN, 1, (LPARAM)(const LV_COLUMN *)(&lvc));
			if ( lpzProto!=NULL)
			{
			// -----------------------------------------------------------------add all status sounds
			for (i = ID_STATUS_MAX; i >= ID_STATUS_MIN; i--) 
			{   int Pflags2 = CallProtoService(lpzProto,PS_GETCAPS,PFLAGNUM_2,0);
			    if (Pflags2 == 0) Pflags2 = PF2_ONLINE|PF2_INVISIBLE|PF2_SHORTAWAY|PF2_LONGAWAY|PF2_LIGHTDND|PF2_HEAVYDND|PF2_FREECHAT|PF2_OUTTOLUNCH|PF2_ONTHEPHONE;
				if ((Proto_Status2Flag(i) != 0 && Pflags2&Proto_Status2Flag(i))
						|| i == ID_STATUS_OFFLINE)
					{ //Offline has not a PF value, so we workaround it :/
					LV_ITEM lvi = { 0 };
					DBVARIANT dbv = { 0 };
					wchar_t  SndFileBuf[63] = L"";
					int dbResult = 0;
					lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
					lvi.iItem = 0;
					lvi.iSubItem = 0;
					lvi.iImage = Index(i); //We've already associated an image list to the listview.
					lvi.lParam = (LPARAM)i;
					lvi.pszText = TranslateTS(StatusesList[Index(i)].lpzStandardText);
					//lvi.iItem = ListView_InsertItem(GetDlgItem(hwndDlg, IDC_INDSNDLIST),&lvi);
					lvi.iItem = SNDMSG(GetDlgItem(hwndDlg, IDC_INDSNDLIST), LVM_INSERTITEM, 0, (LPARAM)(const LV_ITEM *)(&lvi));
					dbResult = DBGetContactSettingTString(hContact, ModuleName, StatusesList[Index(i)].lpzSkinSoundName, &dbv);
					if (dbResult == DB_READ_SUCCESS) 
						{
/*#ifdef UNICODE						
						MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, dbv.pszVal, -1, SndFileBuf, strlen(dbv.pszVal));
						lvi.pszText = SndFileBuf;
#else
						lvi.pszText = dbv.pszVal;
#endif
*/
						lvi.pszText = dbv.ptszVal;
						}
					else
						lvi.pszText = TranslateT("(default sound)");

					{ LV_ITEM _ms_lvi;
					  _ms_lvi.iSubItem = 1;
					  _ms_lvi.pszText = lvi.pszText;
					  SNDMSG((GetDlgItem(hwndDlg, IDC_INDSNDLIST)), LVM_SETITEMTEXT, (WPARAM)lvi.iItem, (LPARAM)(LV_ITEM *)&_ms_lvi);
					}
					if (dbResult == DB_READ_SUCCESS) DBFreeVariant(&dbv);
				}
			}
					// ---------------- add "user from offline" sound settting
					{
					LV_ITEM lvi = { 0 };
					DBVARIANT dbv = { 0 };
					wchar_t  SndFileBuf[63] = L"";
					int dbResult = 0;
					lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
					lvi.iItem = 0;
					lvi.iSubItem = 0;
					lvi.iImage = Index(ID_STATUS_MAX)+1; // additional icon
					lvi.lParam = (LPARAM)1;
					lvi.pszText = TranslateT("From offline");
					lvi.iItem = SNDMSG(GetDlgItem(hwndDlg, IDC_INDSNDLIST), LVM_INSERTITEM, 0, (LPARAM)(const LV_ITEM *)(&lvi));
					dbResult = DBGetContactSettingTString(hContact, ModuleName, "UserFromOffline", &dbv);
					if (dbResult == DB_READ_SUCCESS) 
						{
/*#ifdef UNICODE						
						MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, dbv.pszVal, -1, SndFileBuf, strlen(dbv.pszVal));
						lvi.pszText = SndFileBuf;
#else
						lvi.pszText = dbv.pszVal;
#endif
*/
						lvi.pszText = dbv.ptszVal;
					    }
					else
						lvi.pszText = TranslateT("(default sound)");
					//ListView_SetItemText(GetDlgItem(hwndDlg, IDC_INDSNDLIST),lvi.iItem,1,lvi.pszText);
					{
					LV_ITEM _ms_lvi;
					 _ms_lvi.iSubItem = 1;
					 _ms_lvi.pszText = lvi.pszText;
					 SNDMSG((GetDlgItem(hwndDlg, IDC_INDSNDLIST)), LVM_SETITEMTEXT, (WPARAM)lvi.iItem, (LPARAM)(LV_ITEM *)&_ms_lvi);
					}
					if (dbResult == DB_READ_SUCCESS) DBFreeVariant(&dbv);
					}
			//------------------------------------------end "fromoffline"---
			}
			{  //checkboxes for contact to disable popups and sounds
			BYTE	EnableSounds = DBGetContactSettingByte(hContact,ModuleName,"EnableSounds",1);
			BYTE	EnablePopups = DBGetContactSettingByte(hContact,ModuleName,"EnablePopups",1);
			CheckDlgButton(hwndDlg, IDC_CHECK_NOTIFYSOUNDS, EnableSounds?BST_CHECKED:BST_UNCHECKED);
			CheckDlgButton(hwndDlg, IDC_CHECK_NOTIFYPOPUPS, EnablePopups?BST_CHECKED:BST_UNCHECKED);
			}
			if (MyOptions.UseIndSnd) // if individual sounds are used, then activate all controls
				{
				ShowWindow(GetDlgItem(hwndDlg, IDC_INDSNDLIST), SW_SHOW);
				ShowWindow(GetDlgItem(hwndDlg,IDC_TEXT_ENABLE_IS), SW_HIDE);
				ShowWindow(GetDlgItem(hwndDlg, IDC_CHANGE),  SW_SHOW);
				ShowWindow(GetDlgItem(hwndDlg, IDC_PREVIEW), SW_SHOW);
				ShowWindow(GetDlgItem(hwndDlg, IDC_DELETE), SW_SHOW);
				}
			else
				{
				ShowWindow(GetDlgItem(hwndDlg, IDC_INDSNDLIST), SW_HIDE);
				ShowWindow(GetDlgItem(hwndDlg,IDC_TEXT_ENABLE_IS), SW_SHOW);
				ShowWindow(GetDlgItem(hwndDlg, IDC_CHANGE), SW_HIDE);
				ShowWindow(GetDlgItem(hwndDlg, IDC_PREVIEW), SW_HIDE);
				ShowWindow(GetDlgItem(hwndDlg, IDC_DELETE), SW_HIDE);
				}
				TranslateDialogDefault(hwndDlg);
			return TRUE; //End of WM_INITDIALOG
		}
		case WM_COMMAND: {
			//Who sent us a WM_COMMAND?
			switch (LOWORD(wParam)) {
				case IDC_PREVIEW: {
					//We want to hear the sound.
					HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST);
					int nSel = ListView_GetSelectionMark(hList);
					if ( nSel > -1 ) { //There's something selected.
						LVITEM lvitem = { 0 };
						lvitem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
						lvitem.iItem = ListView_GetNextItem(hList,-1,LVNI_SELECTED);
						ListView_GetItem(hList, &lvitem);
						PreviewSound(hList, lvitem.lParam);
					}
					break;
				} //End of IDC_PREVIEW
				case IDC_CHANGE:
					if (SelectSound(hwndDlg) == TRUE)
						SendMessage(GetParent(hwndDlg), PSM_CHANGED,0,0);
					break;
				case IDC_DELETE:
					if (RemoveSoundFromList(GetDlgItem(hwndDlg, IDC_INDSNDLIST))==TRUE)
						SendMessage(GetParent(hwndDlg), PSM_CHANGED,0,0);
					break;
				case IDC_CHECK_NOTIFYSOUNDS:
					if (IsDlgButtonChecked(hwndDlg, IDC_CHECK_NOTIFYSOUNDS))
						DBDeleteContactSetting(hContact,ModuleName,"EnableSounds");
					else
						DBWriteContactSettingByte(hContact,ModuleName,"EnableSounds",0);
					break;
				case IDC_CHECK_NOTIFYPOPUPS:
					if (IsDlgButtonChecked(hwndDlg, IDC_CHECK_NOTIFYPOPUPS))
						DBDeleteContactSetting(hContact,ModuleName,"EnablePopups");
					else
						DBWriteContactSettingByte(hContact,ModuleName,"EnablePopups",0);
					break;
				default:
					break;
			} //End of SWITCH on WM_COMMAND 
			break; //End of WM_COMMAND
		}
		case WM_NOTIFY:
			switch(((LPNMHDR)lParam)->idFrom) {
				case 0:
					switch (((LPNMHDR)lParam)->code) {
						case PSN_APPLY: {
							//We have to write to the DB: let's find out what.
							TCHAR str[MAX_PATH] = { 0 };
							HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST);
							LVITEM lvitem = { 0 };

							lvitem.mask = LVIF_PARAM;
							//Cycle through the list reading the text associated to each status.
							for(lvitem.iItem = ListView_GetItemCount(hList)-1; lvitem.iItem>=0; lvitem.iItem--) {
								ListView_GetItem(hList,&lvitem);
								ListView_GetItemText(hList,lvitem.iItem,1,str,sizeof(str));
								//If the filename is "(default sound)", delete the setting from the DB, else write the new setting.
								if (lstrcmp(str, TranslateT("(default sound)"))==0) 
									{
									if (lvitem.lParam==1)
										DBDeleteContactSetting((HANDLE)hContact,ModuleName,	"UserFromOffline");
									else 
										DBDeleteContactSetting((HANDLE)hContact,ModuleName,	StatusesList[Index(lvitem.lParam)].lpzSkinSoundName);
									}
								else {
									TCHAR szTranslatedPath[MAX_PATH] = { 0 };
/*#ifdef UNICODE
									char cPath[MAX_PATH] = {0};
									WideCharToMultiByte(CP_ACP,0,str,-1,cPath,MAX_PATH,0,0);
									CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)cPath, (LPARAM)szTranslatedPath);
#else
									CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)str, (LPARAM)szTranslatedPath);
#endif
*/
									CallService(MS_UTILS_PATHTORELATIVET, (WPARAM)str, (LPARAM)szTranslatedPath);
									if (lvitem.lParam==1)
										DBWriteContactSettingTString((HANDLE)hContact,ModuleName, "UserFromOffline",szTranslatedPath);
									else
										DBWriteContactSettingTString((HANDLE)hContact,ModuleName, StatusesList[Index(lvitem.lParam)].lpzSkinSoundName, szTranslatedPath);
								}
							} //End of for, we have written every setting.
							return TRUE;
						}
					}
			}
			//Various actions.
			{
				LPNMHDR pParam = (LPNMHDR)lParam;

				if (pParam == NULL) return TRUE;

				switch ((int)wParam) {
					case IDC_INDSNDLIST: 	{
						switch (pParam->code) {
							case NM_DBLCLK: {
								if (SelectSound(hwndDlg) == TRUE)
									SendMessage(GetParent(hwndDlg), PSM_CHANGED,0,0);
								return TRUE;
							}
							case LVN_KEYDOWN: {
								LPNMLVKEYDOWN pnkd = (LPNMLVKEYDOWN)lParam;
								if (pnkd->wVKey == VK_DELETE)
									RemoveSoundFromList(GetDlgItem(hwndDlg, IDC_INDSNDLIST));
								break;
							} //End of KEYDOWN
						}
					} //End of IDC_INDSNDLIST
				} //end int wParam
				break ;
			} //End of WM_NOTIFY
		default:
			break;
	}
	return FALSE;
}

//========== UserInfo page : Initialization ==========
int UserInfoInitialise(WPARAM wParam, LPARAM lParam)
{
	{
	//Individual Sounds UserInfo details page
	OPTIONSDIALOGPAGE odp = { 0 };
	
	if((HANDLE)lParam == NULL) return 0;
	odp.cbSize = sizeof(odp);
	odp.position = 100000000;
	odp.hInstance = hInst;
	odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_SOUNDS);
	odp.pszTitle = Translate(NAME_OF_UIPAGE);
	odp.pfnDlgProc = DlgProcSoundUIPage;

	CallService(MS_USERINFO_ADDPAGE,wParam,(LPARAM)&odp);
	}
	return 0;
}

static void ResetListOptions(HWND hwndList) 
{
	int i;
	SendMessage(hwndList,CLM_SETBKBITMAP,0,(LPARAM)(HBITMAP)NULL);
	SendMessage(hwndList,CLM_SETBKCOLOR,GetSysColor(COLOR_WINDOW),0);
	SendMessage(hwndList,CLM_SETGREYOUTFLAGS,0,0);
	SendMessage(hwndList,CLM_SETLEFTMARGIN,4,0);
	SendMessage(hwndList,CLM_SETINDENT,10,0);
	for(i=0;i<=FONTID_MAX;i++)
		SendMessage(hwndList,CLM_SETTEXTCOLOR,i,GetSysColor(COLOR_WINDOWTEXT));
	SetWindowLong(hwndList,GWL_STYLE,GetWindowLong(hwndList,GWL_STYLE)|CLS_SHOWHIDDEN);
}

static void SetAllContactIcons(HWND hwndList)
{
	HANDLE hContact,hItem;
	char *szProto;
	DWORD flags;
	BYTE EnableSounds, EnablePopups;

	hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
	do 
		{
		hItem=(HANDLE)SendMessage(hwndList,CLM_FINDCONTACT,(WPARAM)hContact,0);
		if(hItem)
			{
			szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
			if (szProto == NULL) {	flags = 0; EnableSounds =EnablePopups = 0;}
			else 
				{
				flags = CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_1,0); //Status flags
				EnableSounds = DBGetContactSettingByte(hContact,ModuleName,"EnableSounds",1);
				EnablePopups = DBGetContactSettingByte(hContact,ModuleName,"EnablePopups",1);
				}
			//if(PF1_INDIVSTATUS)
				{
				if(SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(0,0))==0xFF)
					SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(0,EnableSounds==TRUE?1:0));
				if(SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(1,0))==0xFF)
					SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(1,EnablePopups==TRUE?2:0));
			}
		}
	}
	while(hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0));
}

static void SetListGroupIcons(HWND hwndList,HANDLE hFirstItem,HANDLE hParentItem,int *groupChildCount)
{
	int typeOfFirst;
	int iconOn[2]={1,1};
	int childCount[2]={0,0},i;
	int iImage;
	HANDLE hItem,hChildItem;

	typeOfFirst=SendMessage(hwndList,CLM_GETITEMTYPE,(WPARAM)hFirstItem,0);
	//check groups
	if(typeOfFirst==CLCIT_GROUP) hItem=hFirstItem;
	else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hFirstItem);
	while(hItem) {
		hChildItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_CHILD,(LPARAM)hItem);
		if(hChildItem) SetListGroupIcons(hwndList,hChildItem,hItem,childCount);
		for( i=0; i < SIZEOF(iconOn); i++)
			if(iconOn[i] && SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,i)==0) iconOn[i]=0;
		hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hItem);
	}
	//check contacts
	if(typeOfFirst==CLCIT_CONTACT) hItem=hFirstItem;
	else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hFirstItem);
	while(hItem) {
		for ( i=0; i < SIZEOF(iconOn); i++) {
			iImage=SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,i);
			if(iconOn[i] && iImage==0) iconOn[i]=0;
			if(iImage!=0xFF) childCount[i]++;
		}
		hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hItem);
	}
	//set icons
	for( i=0; i < SIZEOF(iconOn); i++) {
		SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hParentItem,MAKELPARAM(i,childCount[i]?(iconOn[i]?i+1:0):0xFF));
		if(groupChildCount) groupChildCount[i]+=childCount[i];
	}
}

static void SetAllChildIcons(HWND hwndList,HANDLE hFirstItem,int iColumn,int iImage)
{
	int typeOfFirst,iOldIcon;
	HANDLE hItem,hChildItem;

	typeOfFirst=SendMessage(hwndList,CLM_GETITEMTYPE,(WPARAM)hFirstItem,0);
	//check groups
	if(typeOfFirst==CLCIT_GROUP) hItem=hFirstItem;
	else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hFirstItem);
	while(hItem) {
		hChildItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_CHILD,(LPARAM)hItem);
		if(hChildItem) SetAllChildIcons(hwndList,hChildItem,iColumn,iImage);
		hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hItem);
	}
	//check contacts
	if(typeOfFirst==CLCIT_CONTACT) hItem=hFirstItem;
	else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hFirstItem);
	while(hItem) {
		iOldIcon=SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,iColumn);
		if(iOldIcon!=0xFF && iOldIcon!=iImage) SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(iColumn,iImage));
		hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hItem);
	}
}

BOOL CALLBACK DlgProcSoundOpts2(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {

	static HICON hSoundIcon,hPopupIcon;
	static HANDLE hItemAll;
	HANDLE hList = GetDlgItem(hWnd, IDC_INDSNDLIST);
	hCListClone=(HWND)hList;
		//{char str[100];wsprintf (str, L"msg value is %#x", msg);MessageBox(NULL,str,L"soundopts2",0);}
		//printf("msg = %#x", msg);
	switch (msg) {
		case WM_INITDIALOG: {
			TranslateDialogDefault(hWnd);
			{	HIMAGELIST hImageList;
				hImageList=ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),(IsWinVerXPPlus()?ILC_COLOR32:ILC_COLOR16)|ILC_MASK,3,3);
				ImageList_AddIcon(hImageList,(CallService(MS_SYSTEM_GETVERSION,0,0)>=0x00070002?LoadSkinnedIcon(SKINICON_OTHER_SMALLDOT):LoadIcon(hInst,MAKEINTRESOURCE(IDI_SMALLDOT)) ) );
				ImageList_AddIcon(hImageList,LoadIcon(hInst,MAKEINTRESOURCE(IDI_SOUND)));
				ImageList_AddIcon(hImageList,LoadIcon(hInst,MAKEINTRESOURCE(IDI_POPUP)));
				SendDlgItemMessage(hWnd,IDC_INDSNDLIST,CLM_SETEXTRAIMAGELIST,0,(LPARAM)hImageList);
				hSoundIcon=ImageList_GetIcon(hImageList,1,ILD_NORMAL);
				SendDlgItemMessage(hWnd,IDC_SOUNDICON,STM_SETICON,(WPARAM)hSoundIcon,0);
				hPopupIcon=ImageList_GetIcon(hImageList,2,ILD_NORMAL);
				SendDlgItemMessage(hWnd,IDC_POPUPICON,STM_SETICON,(WPARAM)hPopupIcon,0);
			}
			ResetListOptions((HWND)hList);
			SendDlgItemMessage(hWnd,IDC_INDSNDLIST,CLM_SETEXTRACOLUMNS,2,0);

			{	CLCINFOITEM cii={0};
				cii.cbSize=sizeof(cii);
				cii.flags=CLCIIF_GROUPFONT;
				cii.pszText=TranslateT("** All contacts **");
				hItemAll=(HANDLE)SendDlgItemMessage(hWnd,IDC_INDSNDLIST,CLM_ADDINFOITEM,0,(LPARAM)&cii);
			}

			SetAllContactIcons((HWND)hList);
			SetListGroupIcons((HWND)hList,(HANDLE)SendDlgItemMessage(hWnd,IDC_INDSNDLIST,CLM_GETNEXTITEM,CLGN_ROOT,0),hItemAll,NULL);
			return TRUE;
		}
		case WM_SETFOCUS:
			SetFocus((HWND)hList);
			break;
		case WM_NOTIFY:
/*			{wchar_t str[100];
			wsprintf(str, L"wm notify value %#x", ((LPNMHDR)lParam)->idFrom);
			MessageBox(NULL,str,L"NSN 123456789",0);
			}
*/			switch(((LPNMHDR)lParam)->idFrom) {
				case IDC_INDSNDLIST:
					switch (((LPNMHDR)lParam)->code)
					{
						case CLN_NEWCONTACT:
						case CLN_LISTREBUILT:
							SetAllContactIcons((HWND)hList);
							//fall through
						case CLN_CONTACTMOVED:
							SetListGroupIcons((HWND)hList,(HANDLE)SendMessage((HWND)hList,CLM_GETNEXTITEM,CLGN_ROOT,0),hItemAll,NULL);
							break;
						case CLN_OPTIONSCHANGED:
							ResetListOptions((HWND)hList);
							break;
						case NM_CLICK: 
							{
							HANDLE hItem;
							NMCLISTCONTROL *nm=(NMCLISTCONTROL*)lParam;
							DWORD hitFlags;
							int iImage;
							int itemType;
							// Make sure we have an extra column
							if(nm->iColumn==-1) break;
							// Find clicked item
							hItem=(HANDLE)SendMessage((HWND)hList,CLM_HITTEST,(WPARAM)&hitFlags,MAKELPARAM(nm->pt.x,nm->pt.y));
							// Nothing was clicked
							if(hItem==NULL) break;
							// It was not a sound or popup icon
							if(!(hitFlags&CLCHT_ONITEMEXTRA)) break;
							itemType=SendMessage((HWND)hList,CLM_GETITEMTYPE,(WPARAM)hItem,0);
							// Get image in clicked column (0=none, 1=sound, 2=popup)
							iImage=SendMessage((HWND)hList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(nm->iColumn,0));
							if(iImage==0) iImage=nm->iColumn+1;
							else if(iImage==1 || iImage==2) iImage=0;
							// Get item type (contact, group, etc...)
							// Update list
							if(itemType==CLCIT_CONTACT)
								{
								SendMessage((HWND)hList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(nm->iColumn,iImage));
								}
							else if(itemType==CLCIT_INFO)	 //must be 'all contacts'
								{
								SetAllChildIcons((HWND)hList,hItem,nm->iColumn,iImage);
								}
							else if(itemType==CLCIT_GROUP) {
								hItem=(HANDLE)SendMessage((HWND)hList,CLM_GETNEXTITEM,CLGN_CHILD,(LPARAM)hItem);
								if(hItem) 
									{
									SetAllChildIcons((HWND)hList,hItem,nm->iColumn,iImage);
									}
							}
							// Update the all/none icons
							SetListGroupIcons((HWND)hList,(HANDLE)SendMessage((HWND)hList,CLM_GETNEXTITEM,CLGN_ROOT,0),hItemAll,NULL);
							// Activate Apply button
							SendMessage(GetParent(hWnd), PSM_CHANGED, 0, 0);
							break;
						}
					}
					break;
				case 0:
					switch (((LPNMHDR)lParam)->code)
					{
						case PSN_APPLY: {
							HANDLE hContact,hItem;
							int iImage;
							hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
							do 
								{
								hItem=(HANDLE)SendMessage((HWND)hList,CLM_FINDCONTACT,(WPARAM)hContact,0);
								if(hItem)
									{
									iImage=SendMessage((HWND)hList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(0,0));
									if(iImage==1)
										DBDeleteContactSetting(hContact,ModuleName,"EnableSounds");
									else
										DBWriteContactSettingByte(hContact,ModuleName,"EnableSounds",0);
									iImage=SendMessage((HWND)hList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(1,0));
									if(iImage==2) 
										DBDeleteContactSetting(hContact,ModuleName,"EnablePopups");
									else
										DBWriteContactSettingByte(hContact,ModuleName,"EnablePopups",0);

									}
								}
							while(hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0));
							return TRUE;
						}
					}
					break;
			}
			break;
		case WM_DESTROY: 
			{
			HIMAGELIST hIml = (HIMAGELIST)SendMessage((HWND)hList,CLM_GETEXTRAIMAGELIST,0,0);
			DestroyIcon(hSoundIcon);
			DestroyIcon(hPopupIcon);
			ImageList_Destroy(hIml);
			break;
			}
		default:
			break;
	}
	return FALSE;
}
